//namespace Xfinity.Engine.Plugins
//{
//    public class BezierPatch
//    {
//        private static Matrix basisMatrix = new Matrix(-1, 3, -3, 1, 3, -6, 3, 0, -3, 3, 0, 0, 1, 0, 0, 0);

//        public static Matrix BasisMatrix
//        {
//            get { return basisMatrix; }
//        }
//        #region GeneratedPoints
//        private ushort width;

//        public ushort Width
//        {
//            get { return width; }
//            set { width = value; }
//        }
//        private ushort length;

//        public ushort Length
//        {
//            get { return length; }
//            set { length = value; }
//        }

//        private Vector3 b00;

//        public Vector3 B00
//        {
//            get { return b00; }
//            set { b00 = value; }
//        }
//        private Vector3 b01;

//        public Vector3 B01
//        {
//            get { return b01; }
//            set { b01 = value; }
//        }
//        private Vector3 b02;

//        public Vector3 B02
//        {
//            get { return b02; }
//            set { b02 = value; }
//        }
//        private Vector3 b03;

//        public Vector3 B03
//        {
//            get { return b03; }
//            set { b03 = value; }
//        }
//        private Vector3 b10;

//        public Vector3 B10
//        {
//            get { return b10; }
//            set { b10 = value; }
//        }
//        private Vector3 b11;

//        public Vector3 B11
//        {
//            get { return b11; }
//            set { b11 = value; }
//        }
//        private Vector3 b12;

//        public Vector3 B12
//        {
//            get { return b12; }
//            set { b12 = value; }
//        }
//        private Vector3 b13;

//        public Vector3 B13
//        {
//            get { return b13; }
//            set { b13 = value; }
//        }
//        private Vector3 b20;

//        public Vector3 B20
//        {
//            get { return b20; }
//            set { b20 = value; }
//        }
//        private Vector3 b21;

//        public Vector3 B21
//        {
//            get { return b21; }
//            set { b21 = value; }
//        }
//        private Vector3 b22;

//        public Vector3 B22
//        {
//            get { return b22; }
//            set { b22 = value; }
//        }
//        private Vector3 b23;

//        public Vector3 B23
//        {
//            get { return b23; }
//            set { b23 = value; }
//        }
//        private Vector3 b30;

//        public Vector3 B30
//        {
//            get { return b30; }
//            set { b30 = value; }
//        }
//        private Vector3 b31;

//        public Vector3 B31
//        {
//            get { return b31; }
//            set { b31 = value; }
//        }
//        private Vector3 b32;

//        public Vector3 B32
//        {
//            get { return b32; }
//            set { b32 = value; }
//        }
//        private Vector3 b33;

//        public Vector3 B33
//        {
//            get { return b33; }
//            set { b33 = value; }
//        }
//        #endregion

//        /// <summary>
//        /// Construct a new Bezier patch from 16 arbitrary points.
//        /// </summary>
//        /// <param name="h00"></param>
//        /// <param name="h01"></param>
//        /// <param name="h02"></param>
//        /// <param name="h03"></param>
//        /// <param name="h10"></param>
//        /// <param name="h11"></param>
//        /// <param name="h12"></param>
//        /// <param name="h13"></param>
//        /// <param name="h20"></param>
//        /// <param name="h21"></param>
//        /// <param name="h22"></param>
//        /// <param name="h23"></param>
//        /// <param name="h30"></param>
//        /// <param name="h31"></param>
//        /// <param name="h32"></param>
//        /// <param name="h33"></param>
//        public BezierPatch(ushort width, ushort length, Vector3 h00, Vector3 h01, Vector3 h02, Vector3 h03, Vector3 h10, Vector3 h11, Vector3 h12,
//            Vector3 h13, Vector3 h20, Vector3 h21, Vector3 h22, Vector3 h23, Vector3 h30, Vector3 h31, Vector3 h32, Vector3 h33)
//        {
//            this.width = width;
//            this.length = length;
//            b00 = h00;
//            b30 = h21;
//            b03 = h12;
//            b33 = h22;

//            b01 = b00 + (1 / 6) * (h12 - h10);
//            b02 = b03 - (1 / 6) * (h13 - h11);
//            b10 = b00 + (1 / 6) * (h21 - h01);
//            b20 = b30 - (1 / 6) * (h31 - h11);
//            b31 = b30 + (1 / 6) * (h22 - h20);
//            b32 = b33 - (1 / 6) * (h23 - h21);
//            b13 = b03 + (1 / 6) * (h22 - h02);
//            b23 = b33 - (1 / 6) * (h32 - h12);

//            b11 = b01 + b10 - b00;
//            b21 = b31 + b20 - b30;
//            b12 = b13 + b02 - b03;
//            b22 = b23 + b32 - b33;

//            c0bm = Vector4.Transform(new Vector4(b00.Z, b01.Z, b02.Z, b03.Z), basisMatrix);
//            c1bm = Vector4.Transform(new Vector4(b10.Z, b11.Z, b12.Z, b13.Z), basisMatrix);
//            c2bm = Vector4.Transform(new Vector4(b20.Z, b21.Z, b22.Z, b23.Z), basisMatrix);
//            c3bm = Vector4.Transform(new Vector4(b30.Z, b31.Z, b32.Z, b33.Z), basisMatrix);
//        }
//        public static BezierPatch[][] ConstructFromHeightmap(Texture2D map)
//        {
//            BezierPatch[][] patches = new BezierPatch[map.Width - 1][];
//            for (int i = 0; i < patches.Length; i++)
//            {
//                patches[i] = new BezierPatch[map.Height - 1];
//            }
//            if (map.Format != SurfaceFormat.Color)
//                throw new FormatException();
//            Color[] points = new Color[map.Width * map.Height];
//            map.GetData<Color>(points);
//            Vector3 h00, h01, h02, h03, h10, h11, h12, h13, h20, h21, h22, h23, h30, h31, h32, h33;
//            for (int y = 1; y < map.Height - 1; y++)
//            {
//                for (int x = 1; x < map.Width - 1; x++)
//                {
//                    h00 = new Vector3(x - 1, y - 1, points[(y - 1) * map.Height + x - 1].R);
//                    h01 = new Vector3(x - 1, y, points[y * map.Height + x - 1].R);
//                    h02 = new Vector3(x - 1, y + 1, points[(y + 1) * map.Height + x - 1].R);
//                    h03 = new Vector3(x - 1, y + 2, points[(y + 2) * map.Height + x - 1].R);
//                    h10 = new Vector3(x, y - 1, points[(y - 1) * map.Height + x].R);
//                    h11 = new Vector3(x, y, points[y * map.Height + x].R);
//                    h12 = new Vector3(x, y + 1, points[(y + 1) * map.Height + x].R);
//                    h13 = new Vector3(x, y + 2, points[(y + 2) * map.Height + x].R);
//                    h20 = new Vector3(x + 1, y - 1, points[(y - 1) * map.Height + x + 1].R);
//                    h21 = new Vector3(x + 1, y, points[y * map.Height + x + 1].R);
//                    h22 = new Vector3(x + 1, y + 1, points[(y + 1) * map.Height + x + 1].R);
//                    h23 = new Vector3(x + 1, y + 2, points[(y + 2) * map.Height + x + 1].R);
//                    h30 = new Vector3(x + 2, y - 1, points[(y - 1) * map.Height + x + 2].R);
//                    h31 = new Vector3(x + 2, y, points[y * map.Height + x + 2].R);
//                    h32 = new Vector3(x + 2, y + 1, points[(y + 1) * map.Height + x + 2].R);
//                    h33 = new Vector3(x + 2, y + 2, points[(y + 2) * map.Height + x + 2].R);
//                    patches[x - 1][y - 1] = new BezierPatch(1, 1,
//                        h00, h01, h02, h03,
//                        h10, h11, h12, h13,
//                        h20, h21, h22, h23,
//                        h30, h31, h32, h33);
//                }
//            }

//            return patches;
//        }
//        public BezierPatch()
//        {

//        }

//        public BezierPatch(BezierPatch b)
//        {
//            b00 = b.b00;
//            b01 = b.b01;
//            b02 = b.b02;
//            b03 = b.b03;

//            b10 = b.b10;
//            b11 = b.b11;
//            b12 = b.b12;
//            b13 = b.b13;

//            b20 = b.b20;
//            b21 = b.b21;
//            b22 = b.b22;
//            b23 = b.b23;

//            b30 = b.b30;
//            b31 = b.b31;
//            b32 = b.b32;
//            b33 = b.b33;
//            width = b.width;
//            length = b.length;
//        }
//        Vector4 c0bm, c1bm, c2bm, c3bm;

//        public void Subdivide(BezierPatch input, out BezierPatch left, out BezierPatch right)
//        {
//            left = new BezierPatch(this);
//            CreateLeft(left);

//            ushort tempWidth = (ushort)(width >> 1);


//            right = new BezierPatch(this);
//            right.width = (ushort)(width >> 1);
//            CreateRight(right, tempWidth);
//        }

//        private void CreateLeft(BezierPatch left)
//        {
//            left.b10 = EvaluateHeightAtPoint((b00 + b10) * .5f);
//            left.b11 = EvaluateHeightAtPoint((b01 + b11) * .5f);
//            left.b12 = EvaluateHeightAtPoint((b02 + b12) * .5f);
//            left.b13 = EvaluateHeightAtPoint((b03 + b13) * .5f);

//            left.b20 = EvaluateHeightAtPoint((b10 + b20) * .5f);
//            left.b21 = EvaluateHeightAtPoint((b11 + b21) * .5f);
//            left.b22 = EvaluateHeightAtPoint((b12 + b22) * .5f);
//            left.b23 = EvaluateHeightAtPoint((b13 + b23) * .5f);

//            left.b30 = EvaluateHeightAtPoint((b20 + b30) * .5f);
//            left.b31 = EvaluateHeightAtPoint((b21 + b31) * .5f);
//            left.b32 = EvaluateHeightAtPoint((b22 + b32) * .5f);
//            left.b33 = EvaluateHeightAtPoint((b23 + b33) * .5f);
//            left.width = (ushort)(width >> 1);
//        }

//        private void CreateRight(BezierPatch right, ushort tempWidth)
//        {
//            right.b00 = EvaluateHeightAtPoint((right.b00.X * .5f) + tempWidth, right.b00.Y);
//            right.b01 = EvaluateHeightAtPoint((right.b01.X * .5f) + tempWidth, right.b01.Y);
//            right.b02 = EvaluateHeightAtPoint((right.b02.X * .5f) + tempWidth, right.b02.Y);
//            right.b03 = EvaluateHeightAtPoint((right.b03.X * .5f) + tempWidth, right.b03.Y);

//            right.b10 = EvaluateHeightAtPoint((right.b10.X * .5f) + tempWidth, right.b10.Y);
//            right.b11 = EvaluateHeightAtPoint((right.b11.X * .5f) + tempWidth, right.b11.Y);
//            right.b12 = EvaluateHeightAtPoint((right.b12.X * .5f) + tempWidth, right.b12.Y);
//            right.b13 = EvaluateHeightAtPoint((right.b13.X * .5f) + tempWidth, right.b13.Y);

//            right.b20 = EvaluateHeightAtPoint((right.b20.X * .5f) + tempWidth, right.b20.Y);
//            right.b21 = EvaluateHeightAtPoint((right.b21.X * .5f) + tempWidth, right.b21.Y);
//            right.b22 = EvaluateHeightAtPoint((right.b22.X * .5f) + tempWidth, right.b22.Y);
//            right.b23 = EvaluateHeightAtPoint((right.b23.X * .5f) + tempWidth, right.b23.Y);

//            right.b30 = EvaluateHeightAtPoint((right.b30.X * .5f) + tempWidth, right.b30.Y);
//            right.b31 = EvaluateHeightAtPoint((right.b31.X * .5f) + tempWidth, right.b31.Y);
//            right.b32 = EvaluateHeightAtPoint((right.b32.X * .5f) + tempWidth, right.b32.Y);
//            right.b33 = EvaluateHeightAtPoint((right.b33.X * .5f) + tempWidth, right.b33.Y);
//            right.width = tempWidth;
//        }

//        /// <summary>
//        /// Evaluate the patch.
//        /// </summary>
//        /// <param name="x">The x co-ordinate, from 0-1</param>
//        /// <param name="y">The y co-ordinate, from 0-1</param>
//        /// <returns></returns>
//        public Vector3 EvaluateHeightAtPoint(float x, float y)
//        {
//            float y2 = y * y;
//            float x2 = x * x;
//            Vector4 vy = new Vector4(y * y2, y2, y, 1);
//            Vector4 vx = new Vector4(x * x2, x2, x, 1);
//            float c0, c1, c2, c3;
//            c0 = Vector4.Dot(vy, c0bm);
//            c1 = Vector4.Dot(vy, c1bm);
//            c2 = Vector4.Dot(vy, c2bm);
//            c3 = Vector4.Dot(vy, c3bm);

//            Vector4 vxbm = Vector4.Transform(vx, basisMatrix);
//            return new Vector3(x, y, Vector4.Dot(vxbm, new Vector4(c0, c1, c2, c3)));
//        }

//        public Vector3 EvaluateHeightAtPoint(Vector3 point)
//        {
//            float y2 = point.Y * point.Y;
//            float x2 = point.X * point.X;
//            Vector4 vy = new Vector4(point.Y * y2, y2, point.Y, 1);
//            Vector4 vx = new Vector4(point.X * x2, x2, point.X, 1);
//            float c0, c1, c2, c3;
//            c0 = Vector4.Dot(vy, c0bm);
//            c1 = Vector4.Dot(vy, c1bm);
//            c2 = Vector4.Dot(vy, c2bm);
//            c3 = Vector4.Dot(vy, c3bm);

//            Vector4 vxbm = Vector4.Transform(vx, basisMatrix);
//            return new Vector3(point.X, point.Y, Vector4.Dot(vxbm, new Vector4(c0, c1, c2, c3)));
//        }
//        IndexBuffer ind;
//        VertexBuffer vertBuffer;
//        private int vertsToDraw = 64;

//        public int VertsToDraw
//        {
//            get { return vertsToDraw; }
//            set { vertsToDraw = value; }
//        }

//        public void Draw()
//        {
//            ind = new IndexBuffer(GraphicsHelper.GraphicsDevice, (int)(width * length * sizeof(short)) * 6, ResourceUsage.None, ResourceManagementMode.Automatic, IndexElementSize.SixteenBits);
//            VertexPositionNormalTexture[] verts = new VertexPositionNormalTexture[4 * width * length];
//            vertBuffer = new VertexBuffer(GraphicsHelper.GraphicsDevice, (int)(VertexPositionNormalTexture.SizeInBytes * width * length), ResourceUsage.None, ResourceManagementMode.Automatic);
//            short[] indices = new short[6 * width * length];
//            vertsToDraw = width * length;
//            float increment = 1 / vertsToDraw;

//            for (int x = 0; x < width; x++)
//            {
//                for (int y = 0; y < length; y++)
//                {
//                    verts[x * width * +y] = new VertexPositionNormalTexture(EvaluateHeightAtPoint(x * increment, y * increment), EvaluateNormalAtPoint(x * increment, y * increment), new Vector2(x / width, y / length));
//                }
//            }
//            for (short x = 0; x < width; x++)
//            {
//                for (short y = 0; y < length; y++)
//                {
//                    indices[(x * width + y) + 0] = (short)(x * length + y);
//                    indices[(x * width + y) + 1] = (short)((x + 1) * length + y);
//                    indices[(x * width + y) + 2] = (short)(x * length + 1 + y);
//                    indices[(x * width + y) + 3] = (short)((x + 1) * length + y);
//                    indices[(x * width + y) + 4] = (short)((x + 1) * length + 1 + y);
//                    indices[(x * width + y) + 5] = (short)(x * length + 1 + y);
//                }
//            }
//        }

//        private Vector3 EvaluateNormalAtPoint(float x, float y)
//        {
//            return Vector3.Up;//TODO: do this! :D
//        }
//    }
//}